package common;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.StringTokenizer;
import java.util.TreeMap;

/**
 * Represente un modele CBinomial pour associer à chaque mot, chaque classe (positive ou
 * negative) du jeu d'apprentissage, un parametre Beta(mot,classe).
 * Ce parametre Beta est obtenu grace a l'association entre Mot,Classe,Nb Documents De La Classe
 * dans lesquels apparaet le mot. Il suffit alors, pour trouver un parametre Beta, de faire le ratio :
 * 			
 * 			Beta(Mot,Classe) = (Nb Documents De La Classe Contenant le mot)
 * 												
 * 											/
 * 								
 * 								(Nb Documents De La Classe). 
 * 
 * Ce modele CBinomial prend donc en compte le nombre de documents d'une classe contenant le
 * mot en question, sans se soucier du cas ou le mot peut apparaitre plusieurs fois dans un meme
 * document.
 * @author franck
 *
 */
public class CBinomial {

	/**
	 * Informations de base : nom du fichier d'apprentissage et nom du fichier de test
	 */

	//private File FichierApprentissage;
	private File FichierTest;
	private String nomFichierSauvegarde;
	protected ArrayList<File> listeFichiersApprentissage = new ArrayList<File>();
	protected FileWriter FichierEstimationPolarite;
	protected boolean afficherQuePrediction;
	/**
	 * Suppression ou non des mots outils
	 */

	// 1ER parametre entrant en compte dans l'optimisation du programme
	private static boolean SUPPRESSIONMOTSOUTILS;

	// La liste de mots outils, vide ou non, selon la valeur de la variable booleenne
	// precedente
	private ArrayList<String> lesMotsOutils;

	/**
	 * Creation dictionnaire, a partir du fichier d'apprentissage
	 */

	// On designe comme Pattern de debut de critique :
	// une ligne commeneant par une balise ouvrante "<review" suivie d'un espace,
	// puis de "id='" pour declarer son identifiant, suivi d'un nombre et de "'" pour fermer
	// l'attribut id, puis d'un espace, suivi de "class=', avec un ensemble de caracteres,
	// suivi de "'" pour fermer l'attribut class, et enfin d'un chevron fermant ">".
	// les "\\s*" servent a reconnaitre cette ligne particuliere, meme s'il y'avait
	// des espaces places avant, apres ou a l'interieur de la balise <review>.
	private Pattern debutCritiquePattern = Pattern.compile("\\s*<review\\s* id='((\\d)+)'\\s* class='((\\w)+)'\\s*>\\s*");

	// De meme, on designe le Pattern de fin de critique :
	// une ligne contenant la balise fermante "</review>", avec (ou non) des espaces
	// places avant ou apres cette balise de fermeture.
	private Pattern finCritiquePattern = Pattern.compile("\\s*</review>\\s*");

	// Map : Association <mot, nbOccurences dans le corpus>, 
	// en filtrant les mots outils (si on le souhaite)
	private Map<String,Integer> dictionnaire; 

	// Un map associant : pour chaque mot, pour chaque categorie, le nombre de critiques
	// de la categorie ou on rencontre ce mot
	private Map <String, Map<String,Double>> motCategorieNbCritiques;

	// Pour savoir si le mot existe deja dans la critique courante
	// Vaut 1 si le mot existe deja dans la critique courante
	private Map <String, Integer> ceMotExisteDejaDansLaCritiqueCourante;

	// La categorie de la critique courante ("positive" ou "negative")
	private String categorieCritiqueCourante;

	/**
	 * Filtrage du dictionnaire, a partir d'un seuil de frequence maximal
	 */

	// Frequence maximale d'un mot pour pouvoir etre conserve dans le
	// dictionnaire filtre.
	// 2EME parametre entrant en compte dans l'optimisation du programme
	private static double SEUIL_FREQUENCE_MAXI;

	// Map : mot, nbOccurences en gardant les mots de frequence inferieure au seuil
	private Map<String,Integer> dictionnaireFiltre;	

	// En ayant filtre avec le seuil de frequence
	private Map <String, Map<String,Double>> motCategorieNbCritiquesFiltre;

	/**
	 * Sauvegarde du dictionnaire, du dictionnaire avec nombre d'occurences decroissant,
	 * et de la correspondance Mot,Classe,NombreDeDocuments
	 */

	// Pour les mots qui apparaissent dans aucun document, 
	// ils apparaitront dans K documents (K < 1)
	// 3EME parametre entrant en compte dans l'optimisation du programme
	private static double K;

	/**
	 * Creation et sauvegarde de Mot,Categorie,Parametre
	 */

	// Map permettant d'associer e une classe le nombre de Critiques
	// de cette classe (utile pour le calcul final des parametres Beta(mot,classe))
	private Map <String,Integer> categorieNbCritiques;

	// Le map qui contiendra pour chaque mot, chaque categorie, un parametre Beta
	// associe
	private Map <String, Map<String,Double>> motCategorieParametre;

	/**
	 * Classification et determination du taux de reussite
	 */

	// Nombre de bonnes predictions de classe pour un fichier Test
	private int nbDecisionsCorrectesPourUnJeuDeTest;

	// Nombre de critiques contenues dans le fichier Test
	private int nbCritiquesJeuDeTestCourant;

	// Taux de reussite dans les predictions
	private double tauxReussite;

	/**
	 * Pour afficher des statistiques
	 */

	// Nombre de critiques contenues dans le fichier d'apprentissage
	private int nbCritiques;

	// Nombre de mots total contenu dans le jeu d'apprentissage (en ayant enleve 
	// les mots outils)
	private int nbMotsDuCorpus;

	// Le nombre de critiques positives, negatives du fichier d'apprentissage
	// Utile pour determiner le parametre de chaque mot, chaque categorie
	private int nbCritiquesPositives;
	private int nbCritiquesNegatives;


	/**
	 * Une instance de la classe ModeleBinomial permet de creer un modele, en se basant
	 * sur les informations contenues dans un fichier d'apprentissage "FicApp", pour pouvoir
	 * essayer de classifier les critiques contenues dans le fichier "FicTest".
	 * @param FicApp	le fichier d'apprentissage, contenant des critiques labellisees
	 * @param FicTest	le fichier de test, contenant des critiques dont la classe
	 * (positive ou negative) est à predire
	 * @param suppression	permet d'enlever les mots outils (true) ou pas (false)
	 * @param seuil			correspond au seuil de frequence maximal au-dela duquel les mots
	 * 						du vocabulaire initial ne seront pas retenus
	 * @param k				si un mot n'apparait dans aucun document d'une classe, alors on 
	 * 						considere qu'il apparaet dans k documents de la classe (k < 1)
	 */
	/*public CBinomial(File FicApp, File FicTest,  boolean suppression, double
			seuil, double k){

		// ------------------------------------------
		// Initialisation des parametres pouvant influer l'estimation du jeu de test
		// ------------------------------------------

		SUPPRESSIONMOTSOUTILS = suppression;
		SEUIL_FREQUENCE_MAXI = seuil;
		K = k;

		// ------------------------------------------
		// Initialisation de l'ensemble des variables utilis�es
		// ------------------------------------------

		FichierApprentissage = FicApp;
		FichierTest = FicTest;



		System.out.println("Fichier apprentissage : " + FichierApprentissage.getName());
		System.out.println("Fichier Test : " + FichierTest.getName());

		lesMotsOutils = new ArrayList<String>();
		dictionnaire = new TreeMap<String, Integer>();

		motCategorieNbCritiques = new TreeMap<String, Map<String,Double>>();

		dictionnaireFiltre = new TreeMap<String, Integer>();

		motCategorieNbCritiquesFiltre = new TreeMap<String, Map<String,Double>>();

		categorieNbCritiques = new TreeMap<String, Integer>();

		motCategorieParametre = new TreeMap<String, Map<String,Double>>();


		nbDecisionsCorrectesPourUnJeuDeTest = 0;
		nbCritiquesJeuDeTestCourant = 0;

		tauxReussite = 0.0;


		nbCritiques = 0;
		nbMotsDuCorpus = 0;

		nbCritiquesPositives = 0;
		nbCritiquesNegatives = 0;


		// ------------------------------------------
		// D�but de l'apprentissage
		// ------------------------------------------
		if (SUPPRESSIONMOTSOUTILS)	suppressionMotsOutils();
		creationDictionnaire();

		// Affichage de quelques statistiques (le nombre de mots
		// peut varier selon les valeurs des param�tres consid�r�s)
		System.out.println("Nb Critiques : " + nbCritiques);
		System.out.println("Nb positives : " + nbCritiquesPositives);
		System.out.println("Nb negatives: " + nbCritiquesNegatives);
		System.out.println("Nb Mots Du corpus : " + nbMotsDuCorpus);

		filtrageDictionnaireSeuilMaximum();

		System.out.println("Taille dictionnaire filtr� : " + dictionnaireFiltre.size());

		sauverDictionnaire();
		sauverMotsPlusFrequentsDictionnaire();
		sauverMotCategorieNbDocs();

		creerEtSauvegarderMotCategorieParametre();


		// ------------------------------------------
		// Evaluation d'un jeu de test, par rapport a un jeu d'apprentissage
		// On determine, pour chaque critique du jeu de test, si elle est de classe
		// positive ou negative. Puis, on compare cette prediction avec la classe reelle
		// de la critique. Si on trouve la meme classe, alors cela compte comme une decision
		// correcte supplementaire, sinon on ne fait rien. Dans tous les cas, on retient
		// le nombre total de critiques du jeu de test.
		// ------------------------------------------

		classification();

		tauxReussite = (double)nbDecisionsCorrectesPourUnJeuDeTest/(double)nbCritiquesJeuDeTestCourant;

		sauverTauxReussite();	
	}
	 */
	public CBinomial(ArrayList<File> listeFichiersAp, File FicTest,
			boolean suppression, double seuil, double k, boolean formaterPourQ3, String fichierPredic3) {

		// ------------------------------------------
		// Initialisation des parametres pouvant influer l'estimation du jeu de test
		// ------------------------------------------

		SUPPRESSIONMOTSOUTILS = suppression;
		SEUIL_FREQUENCE_MAXI = seuil;
		K = k;

		// ------------------------------------------
		// Initialisation de l'ensemble des variables utilisees
		// ------------------------------------------

		listeFichiersApprentissage = listeFichiersAp;
		FichierTest = FicTest;
		afficherQuePrediction = formaterPourQ3;
		try {
			FichierEstimationPolarite = new FileWriter(fichierPredic3);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}



		for(File f : listeFichiersApprentissage){
			System.out.println("(Classifieur Multinomial) Fichier apprentissage :" + f.getAbsolutePath());
		}
		System.out.println("(Classifieur Multinomial) Fichier Test : " + FichierTest.getAbsolutePath());

		lesMotsOutils = new ArrayList<String>();
		dictionnaire = new TreeMap<String, Integer>();

		motCategorieNbCritiques = new TreeMap<String, Map<String,Double>>();

		dictionnaireFiltre = new TreeMap<String, Integer>();

		motCategorieNbCritiquesFiltre = new TreeMap<String, Map<String,Double>>();

		categorieNbCritiques = new TreeMap<String, Integer>();

		motCategorieParametre = new TreeMap<String, Map<String,Double>>();


		nbDecisionsCorrectesPourUnJeuDeTest = 0;
		nbCritiquesJeuDeTestCourant = 0;

		tauxReussite = 0.0;


		nbCritiques = 0;
		nbMotsDuCorpus = 0;

		nbCritiquesPositives = 0;
		nbCritiquesNegatives = 0;


		// ------------------------------------------
		// Debut de l'apprentissage
		// ------------------------------------------
		if (SUPPRESSIONMOTSOUTILS)	suppressionMotsOutils();
		creationDictionnaire();

		// Affichage de quelques statistiques (le nombre de mots
		// peut varier selon les valeurs des parametres consideres)
		System.out.println("Nb Critiques : " + nbCritiques);
		System.out.println("Nb positives : " + nbCritiquesPositives);
		System.out.println("Nb negatives: " + nbCritiquesNegatives);
		System.out.println("Nb Mots Du corpus : " + nbMotsDuCorpus);

		filtrageDictionnaireSeuilMaximum();

		System.out.println("Taille dictionnaire filtre : " + dictionnaireFiltre.size());

		sauverDictionnaire();
		sauverMotsPlusFrequentsDictionnaire();
		sauverMotCategorieNbDocs();

		creerEtSauvegarderMotCategorieParametre();


		// ------------------------------------------
		// Evaluation d'un jeu de test, par rapport a un jeu d'apprentissage
		// On determine, pour chaque critique du jeu de test, si elle est de classe
		// positive ou negative. Puis, on compare cette prediction avec la classe reelle
		// de la critique. Si on trouve la meme classe, alors cela compte comme une decision
		// correcte supplementaire, sinon on ne fait rien. Dans tous les cas, on retient
		// le nombre total de critiques du jeu de test.
		// ------------------------------------------

		classification();

		tauxReussite = (double)nbDecisionsCorrectesPourUnJeuDeTest/(double)nbCritiquesJeuDeTestCourant;

		sauverTauxReussite();	


	}

	public void suppressionMotsOutils() {
		// Si on souhaite supprimer les mots-outils, alors on va ouvrir le
		// fichier "mots_outils.txt" et ajouter chacun des mots dans la liste
		// de mots outils

		try {
			// On ouvre le fichier mot_outils.txt
			BufferedReader lecteur = new BufferedReader(new FileReader("mots_outils/mots_outils.txt"));
			String ligne;

			// Pour chaque ligne trouvee...
			while((ligne = lecteur.readLine()) != null){
				// Si cette ligne contient autre chose qu'un blanc, on l'ajoute a la liste
				if(!ligne.isEmpty()){
					lesMotsOutils.add(ligne);
				}
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}

	}



	public void creationDictionnaire(){

		// On recupere les critiques du fichier d'apprentissage
		ArrayList<Critique> lesCritiques = determinerLesCritiques(listeFichiersApprentissage);

		// Pour chaque critique du fichier d'apprentissage
		for(int j = 0; j < lesCritiques.size(); j++){

			// Si elle répertoriée comme positive
			if(lesCritiques.get(j).getTypeCritique().equals("positive")){
				categorieCritiqueCourante = "positive";
				nbCritiquesPositives++;
			}
			// Si elle est négative
			else {
				categorieCritiqueCourante = "negative";
				nbCritiquesNegatives++;
			}

			// A chaque fois qu'on change de fichier, on remet a zero le map
			// disant si le mot rencontre a deja �t� vu dans le meme document ou non
			ceMotExisteDejaDansLaCritiqueCourante = new TreeMap<String, Integer>();

			analyseCritique(lesCritiques.get(j).getContenu());
			nbCritiques++;

			/*	System.out.println("=============================");
			System.out.println("Critique numero : " + lesCritiques.get(j).getIdentifiant());
			System.out.println("Type :  " + lesCritiques.get(j).getTypeCritique());
			System.out.println(lesCritiques.get(j).getContenu());
			System.out.println("=============================");*/
		}
	}

	public ArrayList<Critique> determinerLesCritiques(File fichier) {

		ArrayList<Critique> lesCritiquesARenvoyer = new ArrayList<Critique>();

		try {
			BufferedReader lecteur = new BufferedReader(new FileReader(fichier));
			String ligne;

			int unIdentifiant = 0;
			String unTypeCritique = "";
			String unContenuCritique = "";

			while((ligne = lecteur.readLine()) != null){
				Matcher mDebut = debutCritiquePattern.matcher(ligne);
				Matcher mFin = finCritiquePattern.matcher(ligne);

				// Debut d'une critique, on recupere identifiant et classe
				if(mDebut.matches()){

					String [] lesMorceauxDeLaLigne = ligne.split("'");
					unIdentifiant = Integer.valueOf(lesMorceauxDeLaLigne[1]);
					unTypeCritique = lesMorceauxDeLaLigne[3];
				}
				// Fin de critique, on remet le contenuCritique a "" et on cree une
				// nouvelle ligne
				else if(mFin.matches()){

					lesCritiquesARenvoyer.add(new Critique(unIdentifiant,unTypeCritique,unContenuCritique));
					unContenuCritique = "";
				}
				// Contenu d'une critique qu'on ajoute
				else {
					unContenuCritique += ligne;
				}
			}
		}
		catch(Exception e){
			e.printStackTrace();
		}
		return lesCritiquesARenvoyer;
	}


	public ArrayList<Critique> determinerLesCritiques(ArrayList<File> listeFic) {

		ArrayList<Critique> lesCritiquesARenvoyer = new ArrayList<Critique>();
		for (File f : listeFic) {

			try {
				BufferedReader lecteur = new BufferedReader(new FileReader(f));
				String ligne;

				int unIdentifiant = 0;
				String unTypeCritique = "";
				String unContenuCritique = "";

				while((ligne = lecteur.readLine()) != null){
					Matcher mDebut = debutCritiquePattern.matcher(ligne);
					Matcher mFin = finCritiquePattern.matcher(ligne);

					// Debut d'une critique, on recupere identifiant et classe
					if(mDebut.matches()){

						String [] lesMorceauxDeLaLigne = ligne.split("'");
						unIdentifiant = Integer.valueOf(lesMorceauxDeLaLigne[1]);
						unTypeCritique = lesMorceauxDeLaLigne[3];
					}
					// Fin de critique, on remet le contenuCritique a "" et on cree une
					// nouvelle ligne
					else if(mFin.matches()){

						lesCritiquesARenvoyer.add(new Critique(unIdentifiant,unTypeCritique,unContenuCritique));
						unContenuCritique = "";
					}
					// Contenu d'une critique qu'on ajoute
					else {
						unContenuCritique += ligne;
					}
				}
			}
			catch(Exception e){
				e.printStackTrace();
			}
		}
		return lesCritiquesARenvoyer;
	}

	public void analyseCritique(String contenuCritique) {

		StringTokenizer tokeniseur = new StringTokenizer(contenuCritique, " ");

		// Pour chaque mot trouve sur la ligne...
		while (tokeniseur.hasMoreTokens()) {
			String motCourant = tokeniseur.nextToken();

			//System.out.println("Mot analyse : " + motCourant);
			// Si ce n'est pas un mot outil, ni un nombre...
			if(!lesMotsOutils.contains(motCourant) && motCourant.matches("[a-zA-Z]*")){

				// On incremente le nombre de mots utiles du corpus (sans mots outils)
				nbMotsDuCorpus++;

				// Si le dictionnaire contient deja le mot, on incremente son nombre
				// d'occurences precedent
				if(dictionnaire.containsKey(motCourant)){
					dictionnaire.put(motCourant, dictionnaire.get(motCourant)+ 1);

				}
				else {
					// Sinon on cree une nouvelle entrée dans le TreeMap, avec comme nb
					// d'occurences initial "1"
					dictionnaire.put(motCourant, 1);
				}

				// Si le mot n'existe pas déja dans la critique courante...
				if(!ceMotExisteDejaDansLaCritiqueCourante.containsKey(motCourant)){
					//System.out.println("Mot : " + motCourant + " n'existe pas deja dans fic courant");
					if(motCategorieNbCritiques.containsKey(motCourant)){
						// ... S'il y'a dejà une entree pour le mot, et la categorie en cours...
						if(motCategorieNbCritiques.get(motCourant).containsKey(categorieCritiqueCourante)){
							motCategorieNbCritiques.get(motCourant).put(categorieCritiqueCourante, motCategorieNbCritiques.get(motCourant).get(categorieCritiqueCourante) + 1);

						}
						// ... sinon ...
						else {
							motCategorieNbCritiques.get(motCourant).put(categorieCritiqueCourante, (double) 1);
						}
					}
					else {
						TreeMap<String, Double> categorieNbCritiques = new TreeMap<String, Double>();
						categorieNbCritiques.put(categorieCritiqueCourante, (double) 1);
						motCategorieNbCritiques.put(motCourant, categorieNbCritiques);
					}
					ceMotExisteDejaDansLaCritiqueCourante.put(motCourant, 1);
				}
			}
		}
	}

	public void filtrageDictionnaireSeuilMaximum() {

		for (String motCourant : dictionnaire.keySet()){
			if((((double)dictionnaire.get(motCourant) / nbMotsDuCorpus) < SEUIL_FREQUENCE_MAXI)){
				dictionnaireFiltre.put(motCourant, dictionnaire.get(motCourant));
				motCategorieNbCritiquesFiltre.put(motCourant, motCategorieNbCritiques.get(motCourant));
			}
		}
	}
	public void sauverDictionnaire() {
		System.out.println("Sauve dico");
		PrintWriter ecrivain = null;

		try {
			ecrivain =  new PrintWriter(new BufferedWriter
					(new FileWriter("dictionnaireTrieParMot.txt")));
		} catch (IOException e) {

			e.printStackTrace();
		}

		for (Entry<String, Integer> entreeCourante : dictionnaireFiltre.entrySet()){
			ecrivain.println("Mot : " + entreeCourante.getKey() + ", Nb Occ : " 
					+ entreeCourante.getValue());
		}
		ecrivain.close();
	}

	public void sauverMotsPlusFrequentsDictionnaire() {
		System.out.println("Sauve mots les plus frequents");

		List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(dictionnaireFiltre.entrySet());
		Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {

			@Override
			public int compare(Entry<String, Integer> o1,
					Entry<String, Integer> o2) {
				return (o2.getValue().compareTo(o1.getValue()));
			}
		});
		PrintWriter ecrivain = null;

		try {
			ecrivain =  new PrintWriter(new BufferedWriter
					(new FileWriter("dictionnaireTrieParNbOccDecroissant.txt")));
		} catch (IOException e) {

			e.printStackTrace();
		}

		for(Entry<String, Integer> entreeCourante : list){
			//System.out.println("J'ecris le mot " + entreeCourante.getKey() + " dans le fichier");
			ecrivain.println("Mot : " + entreeCourante.getKey() + ", Nb Occ : " 
					+ entreeCourante.getValue());
		}
		ecrivain.close();
	}

	public void sauverMotCategorieNbDocs(){
		System.out.println("Sauve MotCategorieNbDocs");
		// Avant de sauver le map MotCategorieNbDocs, on va gerer le cas ou un mot n'apparait dans
		// aucun document

		for(String mot : motCategorieNbCritiquesFiltre.keySet()){
			if(!motCategorieNbCritiquesFiltre.get(mot).containsKey("positive")){
				motCategorieNbCritiquesFiltre.get(mot).put("positive",K);
			}
			if(!motCategorieNbCritiquesFiltre.get(mot).containsKey("negative")){
				motCategorieNbCritiquesFiltre.get(mot).put("negative",K);
			}
		}

		// Ecriture dans un fichier de sortie
		PrintWriter ecrivain = null;

		try {
			ecrivain =  new PrintWriter(new BufferedWriter
					(new FileWriter("MotCategorieNbDocs.txt")));
		} catch (IOException e) {

			e.printStackTrace();
		}

		for(String mot : motCategorieNbCritiquesFiltre.keySet()){
			ecrivain.print(mot);
			for(String categorie : motCategorieNbCritiquesFiltre.get(mot).keySet()){
				ecrivain.println("\t" + categorie + "----->" + motCategorieNbCritiquesFiltre.get(mot).get(categorie));
			}
		}
		ecrivain.close();
	}

	/**
	 * Cette fonction permet, e partir du nombre d'occurences de chaque mot dans
	 * chaque classe (motCategorieNbOccFiltre) et du nombre d'occurences de TOUS les mots
	 * dans chaque classe (categorieNbMotsDansToutesLesCritiquesDeLaCategorie), de deduire
	 * le parametre Beta(mot, classe), correspondant a : 
	 * Beta(Mot,Classe) = (Nb Documents De La Classe Contenant le mot)
	 * 												
	 * 											/
	 * 								
	 * 								(Nb Documents De La Classe). 
	 * 
	 */
	public void creerEtSauvegarderMotCategorieParametre() {

		System.out.println("Sauve motCategorieParametre");
		// Ecriture dans un fichier de sortie
		PrintWriter ecrivain = null;

		try {
			ecrivain =  new PrintWriter(new BufferedWriter
					(new FileWriter("MotCategorieParametre.txt")));
		} catch (IOException e) {

			e.printStackTrace();
		}

		// Recuperation du nb de docs par categorie
		categorieNbCritiques.put("positive", nbCritiquesPositives);
		categorieNbCritiques.put("negative", nbCritiquesNegatives);

		// Calcul de chaque parametre pour chaque mot, chaque categorie
		for(String mot : motCategorieNbCritiquesFiltre.keySet()){

			ecrivain.print(mot);
			for(String categorie : motCategorieNbCritiquesFiltre.get(mot).keySet()){

				if(!motCategorieParametre.containsKey(mot)){
					TreeMap<String, Double> categorieParametre = new TreeMap<String, Double>();
					categorieParametre.put(categorie,  motCategorieNbCritiquesFiltre.get(mot).get(categorie) / categorieNbCritiques.get(categorie));
					motCategorieParametre.put(mot, categorieParametre);
				}
				else {
					motCategorieParametre.get(mot).put(categorie,  motCategorieNbCritiquesFiltre.get(mot).get(categorie) / categorieNbCritiques.get(categorie));
				}

				ecrivain.println("\t" + categorie + "----->" + 
						(motCategorieNbCritiquesFiltre.get(mot).get(categorie) / categorieNbCritiques.get(categorie)));
			}
		}
		ecrivain.close();
	}

	/**
	 * Fonction classification() permettant ici, pour un domaine, de prendre
	 * chaque critique du fichier de test et de regarder si la logVraiSemblance
	 * la plus grande correspond bien à la polarité réelle de la critique. Si c'est
	 * le cas, c'est considéré comme une nouvelle décision correcte pour ce jeu
	 * de test. (ce qui permet de déterminer le taux de réussite)
	 */
	public void classification() {

		ArrayList<Critique> lesCritiquesAEvaluer = determinerLesCritiques(FichierTest);
		PrintWriter ecrivain_justlab =  new PrintWriter(new BufferedWriter(FichierEstimationPolarite));

		System.out.println("Nombre critiques du fichier test : " + lesCritiquesAEvaluer.size());	
		double logVraiSemblanceVraieCategorie;
		double logVraiSemblanceAutreCategorie;

		for(int i = 0; i < lesCritiquesAEvaluer.size(); i++){
            
            //System.out.println("Traitement critique numero " + lesCritiquesAEvaluer.get(i).getIdentifiant());
            nbCritiquesJeuDeTestCourant++;
            
                 // si on predut dvd/unlab.txt
            if(afficherQuePrediction){
            	if (logVraisemblance(lesCritiquesAEvaluer.get(i).getContenu(), "positive") > 
            	logVraisemblance(lesCritiquesAEvaluer.get(i).getContenu(), "negative")) {            		
            		ecrivain_justlab.println("<review id='"+lesCritiquesAEvaluer.get(i).getIdentifiant() + "' class='positive'>");		            		
            	}
            	else {
            		ecrivain_justlab.println("<review id='"+lesCritiquesAEvaluer.get(i).getIdentifiant() + "' class='negative'>");
            	}
            	
            	
            }
            
            // sinon
            else {
            if(lesCritiquesAEvaluer.get(i).getTypeCritique().equals("positive")){            	

                    logVraiSemblanceVraieCategorie = logVraisemblance(lesCritiquesAEvaluer.get(i).getContenu(), "positive");
                    logVraiSemblanceAutreCategorie = logVraisemblance(lesCritiquesAEvaluer.get(i).getContenu(), "negative");
            }
            else {            	
                    logVraiSemblanceVraieCategorie = logVraisemblance(lesCritiquesAEvaluer.get(i).getContenu(), "negative");
                    logVraiSemblanceAutreCategorie = logVraisemblance(lesCritiquesAEvaluer.get(i).getContenu(), "positive");
            }
            if(logVraiSemblanceVraieCategorie > logVraiSemblanceAutreCategorie){
                    nbDecisionsCorrectesPourUnJeuDeTest++;
            }
    }
		}
		ecrivain_justlab.close();

	}

	public double logVraisemblance(String uneCritique, String categorie){
		Map <String,Integer> motPresent = new HashMap<String, Integer>();

		double logVraisemblance = 0;
		String categorieDuFichier = categorie;

		// Chaque mot d'une critique est separe par un espace dans le fichier de test
		StringTokenizer tokeniseur = new StringTokenizer(uneCritique, " ");

		// Pour chaque mot trouve sur la ligne...
		while (tokeniseur.hasMoreTokens()) {
			String motCourant = tokeniseur.nextToken();

			// Si ce n'est pas un mot outil, ni un nombre...
			// Autrement dit : si c'est un mot appartenant au dictionnaire filtre...
			if(dictionnaireFiltre.containsKey(motCourant)){
				motPresent.put(motCourant, 1);
			}
		}

		for(String mot : dictionnaireFiltre.keySet()){
			if(!motPresent.containsKey(mot)){
				motPresent.put(mot, 0);
			}
			if(motPresent.get(mot) == 1){
				logVraisemblance += Math.log(motCategorieParametre.get(mot).get(categorieDuFichier));
			}
			if(motPresent.get(mot) == 0){
				logVraisemblance += Math.log(1 - (motCategorieParametre.get(mot).get(categorieDuFichier)));
			}
		}

		return logVraisemblance;
	}

	public void sauverTauxReussite() {

		PrintWriter ecrivain = null;

		try {
			ecrivain =  new PrintWriter(new BufferedWriter
					(new FileWriter("tauxReussiteBinomial.txt")));
		} catch (IOException e) {

			e.printStackTrace();
		}
		ecrivain.println("---------------------");
		ecrivain.println("Taux réussite : " + tauxReussite);
		if (!afficherQuePrediction) System.out.println("Taux de réussite = " +tauxReussite);
		ecrivain.close();
	}
	/**
	 * Ecrit dans un fichier CSV, pour chaque ligne, le taux de reussite
	 * en fonction de la valeur courante du seuil de filtre, du parametre K et de la
	 * suppression (ou non) des mots outils
	 * @param ecrivain 
	 */
	public void MAJFichierCSVInfluenceSeuilFrequenceEtK(PrintWriter ecrivain){
		ecrivain.println(SUPPRESSIONMOTSOUTILS+";"+SEUIL_FREQUENCE_MAXI+";"+K+";"+dictionnaireFiltre.size()+";"+tauxReussite);
		ecrivain.flush();
	}

	public double getTauxReussite() {
		return tauxReussite;
	}


	/*
	public static void main(String args[]){
		try {

			long start = System.currentTimeMillis(); 


			 // Avec les mots outils (SUPPRESSION = false)


			PrintWriter ecrivain;
			ecrivain =  new PrintWriter(new BufferedWriter(new FileWriter("Binomial_influence_parametres_avec_mots_outils.csv")));

			ecrivain.println("MOTS_OUTILS_SUPPRIMES;SEUIL_FREQUENCE;K;NB_MOTS_DICO_FILTRE;TAUX_REUSSITE");



			 // Sans les mots outils (SUPPRESSION = true)


			PrintWriter ecrivain2;
			ecrivain2 =  new PrintWriter(new BufferedWriter(new FileWriter("Binomial_influence_parametres_sans_mots_outils.csv")));

			ecrivain2.println("MOTS_OUTILS_SUPPRIMES;SEUIL_FREQUENCE;K;NB_MOTS_DICO_FILTRE;TAUX_REUSSITE");

			// Valeurs initiales du seuil et de k
			double seuil = 0.1;
			double k = 0.1;

			// Influence du seuil de frequence sur le taux de reussite
			// + Influence de la variable K
			while(seuil > 0.00099){
				while(k < 1){
					System.out.println(">>>>>>> SEUIL_FREQUENCE_MAXI = " + SEUIL_FREQUENCE_MAXI + "<<<<<<<<");
					System.out.println(">>>>>>> K = " + K + "<<<<<<<<");

					// Cas oe on garde les mots outils, on sauvegarde les resultats
					// des taux de reussite dans un 1er fichier CSV
					CBinomial mb = new CBinomial
					(listeFichiersApprentissagee, new File("books/dev.txt"), false,
							seuil,k);

					mb.MAJFichierCSVInfluenceSeuilFrequenceEtK(ecrivain);

					// Cas oe on enleve les mots outils, on sauvegarde les resultats
					// des taux de reussite dans un 2eme fichier CSV
					CBinomial mb2 = new CBinomial
					(new File("books/training.txt"), new File("books/dev.txt"),true,seuil,k);

					mb2.MAJFichierCSVInfluenceSeuilFrequenceEtK(ecrivain2);


					// On fait varier K pour avoir differentes valeurs de taux de reussite
					K = K + 0.02;

					// On fait varier K pour avoir differentes valeurs de taux de reussite
					k = k + 0.05;

				}

				// On fait varier le seuil de frequence pour avoir differentes valeurs de taux de reussite
				SEUIL_FREQUENCE_MAXI = SEUIL_FREQUENCE_MAXI - 0.002;
				K = 0.95;

				// On fait varier le seuil de frequence pour avoir differentes valeurs de taux de reussite
				seuil = seuil / 10;
				k = 0.1;

			}

			// On ferme les 2 fichiers CSV
			ecrivain.close();
			ecrivain2.close();

			long time= System.currentTimeMillis(); 
			System.out.println("Programme : " + (((time - start)/1000)) + "secondes");
		}
		catch (Exception e){
			e.printStackTrace();
		}
	}*/
}
